Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration tests #148

Merged
merged 21 commits into from
Oct 24, 2024
Merged

Integration tests #148

merged 21 commits into from
Oct 24, 2024

Conversation

QuentinI
Copy link
Contributor

@QuentinI QuentinI commented Sep 30, 2024

This PR:

Adds an integration testing "framework" based on HotShot test harness.
Integration tests for builder are based on implementing TestBuilderImplementation, which allows running HotShot test harness with custom builder implementation. Additionally, this PR implements two TestTasks that can be injected into HotShot harness:

  • TransactionGenerationTask, which allows for more flexible transaction generation than what's provided in HotShot harness
  • BuilderValidationTask, which applies custom validation logic to verify builder-related properties of the chain. Currently it only verifies transaction ordering and a transaction count threshold, but can be extended to verify other properties as needed, e.g. latency.

This PR does not:

  • Planned, but not included: integration testing for legacy builder: best done after BuilderState refactor to re-use most of the code from marketplace builder
  • Add a significant amount of tests: some basic tests are present in crates/marketplace/src/testing/integration.rs

Key places to review:

@QuentinI QuentinI marked this pull request as draft September 30, 2024 12:35
@QuentinI QuentinI force-pushed the ag/integration branch 2 times, most recently from 9d274d2 to f502edd Compare October 10, 2024 16:38
@QuentinI QuentinI changed the base branch from main to ag/shared-crate October 16, 2024 12:33
Base automatically changed from ag/shared-crate to main October 16, 2024 15:24
@QuentinI QuentinI marked this pull request as ready for review October 16, 2024 17:08
@QuentinI QuentinI changed the title [WIP] integration tests Integration tests Oct 16, 2024
@coveralls
Copy link

coveralls commented Oct 17, 2024

Pull Request Test Coverage Report for Build 11481521970

Details

  • 1 of 318 (0.31%) changed or added relevant lines in 7 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-7.3%) to 71.937%

Changes Missing Coverage Covered Lines Changed/Added Lines %
crates/shared/src/utils.rs 0 2 0.0%
crates/legacy/src/service.rs 0 3 0.0%
crates/shared/src/testing/mod.rs 0 37 0.0%
crates/shared/src/testing/validation.rs 0 51 0.0%
crates/marketplace/src/testing/integration.rs 0 100 0.0%
crates/shared/src/testing/generation.rs 0 124 0.0%
Totals Coverage Status
Change from base Build 11480896880: -7.3%
Covered Lines: 2384
Relevant Lines: 3314

💛 - Coveralls

Copy link
Contributor

@dailinsubjam dailinsubjam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would appreciate if we could have a description about this PR. More comments in crates/marketplace/src/testing/integration.rs would also be helpful for review. Thanks!

@QuentinI
Copy link
Contributor Author

QuentinI commented Oct 22, 2024

@dailinsubjam done, hopefully description + additional comments will be helpful. Please request more docs if not, there's no such thing as enough docs 🙂

{
type Event = Event<Types>;

async fn handle_event(&mut self, (event, id): (Self::Event, usize)) -> anyhow::Result<()> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't know we could define names like (event, id) here!

Copy link
Contributor Author

@QuentinI QuentinI Oct 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 78 to 80
if id != 0 {
return Ok(());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment about what id is and why we can return Ok if it's nonzero?

if let Err(e) = self
.txn_history
.iter()
.map(|txn| txn.payload.number as i64)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the code here I feel like index is probably a better field name than number, to distinguish it from "count".

Comment on lines 205 to 207
if id != 0 {
return Ok(());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, can you add a comment about id and why we return Ok here?

// If the builder returns an error, we will re-try on the next view
error => {
tracing::warn!(?error, "Builder API error");
self.txn_queue.push_front(txn);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we push to txn_queue if the submission fails?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To try again next view, so that transactions we submit to the builder are numbered sequentially, otherwise we wouldn't be able to determine whether ordering failed because something's wrong with the builder or because one of transactions was rejected by the builder

n_nodes: usize,
url: Url,
config: Self::Config,
_changes: HashMap<u64, BuilderChange>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this argument for future tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is required by the trait, in HotShot it is used to test how network behaves when some of the builders go offline / restart / start failing responses. As it mostly used to test proposer behavior rather than the builder's, I decided to ignore it here, although maybe we'll want to make use of it in some more complex tests

Comment on lines +184 to +187
fn start(
self: Box<Self>,
stream: Box<
dyn futures::prelude::Stream<Item = hotshot::types::Event<Types>>
Copy link
Contributor

@dailinsubjam dailinsubjam Oct 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like start() in implementation of trait TestBuilderImplementation is for starting [ProxyGlobalState] APIs and initial [BuilderState]'s event loop (as the comment said). Then what's this start() for? What's the difference between run_builder_service() and starting the event loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run_builder_service starts a task that takes a hotshot event stream and processes events from it (applies hooks and forwards to builder states)
The naming is rather non-intuitive I think, something to address during the upcoming refactor.

Comment on lines +30 to +32
/// - `Random` submits a certain amount of random transactions every view
/// - `Seeded` accepts a map of transactions to submit on each view
/// - `Flood` continually submits transactions, re-trying if it encounters an error on
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this!

.iter()
.map(|txn| txn.payload.index as i64)
.try_fold(-1, |prev, next| {
if prev + 1 == next {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we allow silent drop here? If so we might want to change to prev < next

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was writing this before we even figured out silent drop exists, but I'd leave it as is nonetheless because silent drop is extremely unlikely to happen in integration tests because all nodes behave and network is as good as it gets, so we won't trigger the silent drop accidentally. So I'd leave this check as-is because failure here would be very likely indication of another bug in builder rather than silent drop issue.
Then, as part of fixing the silent drop, we can specifically engineer a test where conditions for it happen in a reproducible manner.

@QuentinI QuentinI merged commit 87c19be into main Oct 24, 2024
7 checks passed
@QuentinI QuentinI deleted the ag/integration branch October 24, 2024 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants